Skip to content

Conversation

@jsoningram
Copy link
Contributor

Asana Task/Github Issue: https://app.asana.com/1/137249556945/project/1211050482669423/task/1212009313322049?focus=true

Description

Testing Steps

Checklist

Please tick all that apply:

  • I have tested this change locally
  • I have tested this change locally in all supported browsers
  • This change will be visible to users
  • I have added automated tests that cover this change
  • I have ensured the change is gated by config
  • This change was covered by a ship review
  • This change was covered by a tech design
  • Any dependent config has been merged

@netlify
Copy link

netlify bot commented Nov 27, 2025

Deploy Preview for content-scope-scripts ready!

Name Link
🔨 Latest commit dddd9a8
🔍 Latest deploy log https://app.netlify.com/projects/content-scope-scripts/deploys/692fc88c2aa54b00081fd2be
😎 Deploy Preview https://deploy-preview-2063--content-scope-scripts.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link

github-actions bot commented Nov 27, 2025

Temporary Branch Update

The temporary branch has been updated with the latest changes. Below are the details:

Please use the above install command to update to the latest version.

@github-actions
Copy link

github-actions bot commented Nov 27, 2025

[Beta] Generated file diff

Time updated: Wed, 03 Dec 2025 16:47:16 GMT

Apple
    - apple/pages/new-tab/dist/index.css
  • apple/pages/new-tab/dist/index.js

File has changed

Integration
    - integration/pages/new-tab/dist/index.css
  • integration/pages/new-tab/dist/index.js

File has changed

Windows
    - windows/pages/new-tab/dist/index.css
  • windows/pages/new-tab/dist/index.js

File has changed

@jsoningram jsoningram force-pushed the jingram/cpm-stats-on-ntp-scroll branch 2 times, most recently from cd0e5bc to 1e6a692 Compare December 2, 2025 00:21
Handle undefined trackingStatus when sites are first logged. The
component now provides a safe default and reactively updates when
tracking status data arrives, fixing the issue where "no trackers
blocked" was shown initially even when trackers were actually blocked.
Updated the component to use reactive computed signals. Changes:
  1. `trackingStatus` — computed signal tracking
activity.value.trackingStatus[id]
  2. `totalTrackersBlocked` — computed signal derived from
trackingStatus
  3. `totalTrackersPillText` — computed signal that updates when the
count changes
  4. `cookiePopUpBlocked` — kept as a computed signal (removed the
.value that read it once)
1. Added `useSignalEffect`: Tracks when computed signals
(totalTrackersPillText, totalTrackersBlocked, cookiePopUpBlocked)
change.
2. Used a ref to track previous values: prevValuesRef stores the last
values to avoid unnecessary re-renders.
3. State update on change: When computed values change, update state via
setRenderKey to trigger a re-render.
4. Conditional updates: Only update state when values actually change,
reducing unnecessary re-renders.

How it works:
• useSignalEffect runs whenever the computed signals change.
• It compares current values with previous values stored in the ref.
• If values changed, it updates the ref and calls setRenderKey to force
a re-render.
• The re-render causes TickPill to display the updated values.
1. Created `activityData` computed: Tracks activity.value directly so
when normalizeData creates a new object (line 228 in
NormalizeDataProvider), this computed re-evaluates.
2. Updated all computed signals: They now depend on activityData.value
instead of activity.value directly, ensuring they re-evaluate when
activityData changes.
3. Added `useSignalEffect`: Tracks activityData changes and forces a
re-render via state update when activity.value changes.
4. Access computed values during render: Accessing .value during render
(not just in JSX) ensures Preact Signals tracks them for reactivity.

How it works:
• When trackingStatus data arrives via activity_onDataUpdate or
activity_onDataPatch, normalizeData runs
• normalizeData creates a new activity.value object (new reference)
• activityData computed detects the change and re-evaluates
• All dependent computed signals (trackingStatus, totalTrackersBlocked,
etc.) re-evaluate
• useSignalEffect runs and calls setRenderKey to force a re-render
• Component re-renders with updated TickPill values
@jsoningram jsoningram force-pushed the jingram/cpm-stats-on-ntp-scroll branch from 44145c0 to 7ea8fea Compare December 2, 2025 20:06
@jsoningram jsoningram force-pushed the jingram/cpm-stats-on-ntp-scroll branch from 7ea8fea to aa46504 Compare December 2, 2025 21:07
Issue fixed: duplicate subscription

  • Before: Two subscriptions to activity_onBurnComplete (one in
BatchedActivityService, one in ProtectionsProvider)
  • After: Only one subscription exists (in BatchedActivityService). We
listen to the custom event it dispatches instead of creating a
duplicate.

  Implementation details

  1. No duplicate subscription: Only BatchedActivityService subscribes
to activity_onBurnComplete (line 93 in batched-activity.service.js).
  2. Event listener setup: useBlockedCount listens to the custom event
from BatchedActivityService.burns EventTarget (lines 122-137).
  3. Conditional setup: The listener is set up only when
ActivityProvider is mounted (when feed is 'activity'). This is correct
because:
    • Burns only occur when viewing the activity feed
    • The listener is set up when activityService becomes available
    • The effect dependency array includes activityService, so it
re-runs when the service becomes available
  4. Cleanup: The cleanup function captures the burns reference directly
(line 130), ensuring proper cleanup even if activityService is
destroyed/unmounted.
  5. Shared state: burnCompleteTimeRef is shared via
BurnCompleteTimeContext, so all useBlockedCount hooks share the same
burn complete time.

  Edge cases handled

  1. Feed switching: When switching from 'activity' to 'privacy-stats',
ActivityProvider unmounts, the service is destroyed, and the listener is
cleaned up.
  2. Initial render: If feed is not 'activity', activityService is {}
(default), the effect returns early, and no listener is set up
(correct).
  3. Late mount: If ActivityProvider mounts after useBlockedCount runs,
the effect re-runs when activityService becomes available and sets up
the listener.
  4. Service destruction: When BatchedActivityService is destroyed,
burns is set to null, and the cleanup uses optional chaining to handle
this safely.
@jsoningram jsoningram force-pushed the jingram/cpm-stats-on-ntp-scroll branch 9 times, most recently from 43d86ac to bda2ef0 Compare December 3, 2025 01:10
DEBUG

DEBUG

DEBUG
@jsoningram jsoningram force-pushed the jingram/cpm-stats-on-ntp-scroll branch from bda2ef0 to d3f3e76 Compare December 3, 2025 01:17
@jsoningram
Copy link
Contributor Author

Duplicate

@jsoningram jsoningram closed this Dec 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant